#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sqlite3.h>
#include "common.h"
#include <pthread.h>

time_t last_time = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void *heartbeat_thread(void *arg)
{
	int sockfd = *(int *)arg;

	while(1) 
	{
		pthread_mutex_lock(&mutex);
		time_t current_time = time(NULL);
		time_t sleep_time = current_time - last_time;
		pthread_mutex_unlock(&mutex);
		if(sleep_time >= HEARTBEAT_TIME)
		{
			if(send_msg(sockfd, HEARTBEAT, 0, NULL, 0) < 0) {
				break;
			}
			printf("Heartbeat sent\n");
			last_time = time(NULL);
		}
		sleep(1);
	}

	return NULL;
}

void *recv_thread(void *arg) 
{
	int sockfd = *(int *)arg;
	int ret;

	while(1) 
	{
		char buf[1024] = {0};
		ret = recv_msg(sockfd, buf);
		if(ret < 0)
		{
			break;
		}

		last_time = time(NULL);

		ret = client_process_msg(sockfd, buf);
		if(ret < 0)
		{
			break;
		}
	}

	return NULL;
}


int main(int argc,char *argv[])
{
	if(argc != 3)
	{
		printf("usage : %s serverip port\n",argv[0]);
		return -1;
	}

	int sockfd = -1;
	int ret;
	struct sockaddr_in saddr;
	// 创建TCP socket
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (sockfd == -1)
	{
		perror("socket failed");
		return -1;
	}
	printf("client socket:%d\n",sockfd);
	// 2. 连接服务器
	memset(&saddr,0,sizeof(saddr));
	saddr.sin_family = AF_INET;
	saddr.sin_port = htons(atoi(argv[2]));
	saddr.sin_addr.s_addr = inet_addr(argv[1]);
	ret = connect(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));
	if(ret < 0)
	{
		perror("connect failed");
		close(sockfd);
		return -1;
	}
	printf("Connected to server %s:%s\n", argv[1], argv[2]);
	if(database_init() != 0)
	{
		close(sockfd);
		return -1;
	}
	pthread_t recv_tid;
	if(pthread_create(&recv_tid, NULL, recv_thread, (void *)&sockfd) != 0)
	{
		perror("pthread_create failed");
		close(sockfd);
		return -1;
	}
	pthread_t heartbeat_tid = 0;


	char sign[33] = {0};
	char buf[1024] = {0};
	if(!g_register) 
	{
		register_request_t reg;
		memset(&reg, 0, sizeof(reg));
		strcpy(reg.serial, "0c16d06a45914b758ca226ef325422a3");
		strcpy(reg.mac, "8CEC4B91040C");
		snprintf(reg.timestamp, sizeof(reg.timestamp), "%ld", time(NULL));
		strcpy(reg.type, "KG02");
		generate_signature(reg.serial, reg.mac, reg.timestamp, sign);
		memcpy(reg.sign, sign, sizeof(reg.sign));
		send_msg(sockfd, REQUEST, REGISTER, &reg, sizeof(reg));
		memset(buf,0,sizeof(buf));
		sleep(3);

		if(!g_register)
		{
			printf("register failed\n");
			return -1;
		}

		login_request_t login;
		memset(&login, 0, sizeof(login));
		memcpy(login.uuid, g_uuid, sizeof(login.uuid));
		strcpy(login.version, "V1.0.0");
		snprintf(login.timestamp, sizeof(login.timestamp), "%ld", time(NULL));
		generate_signature(login.uuid, g_passwd, login.timestamp, sign);
		memcpy(login.sign, sign, sizeof(login.sign));
		send_msg(sockfd, REQUEST, LOGIN, &login, sizeof(login));
		memset(buf, 0, sizeof(buf));
		sleep(3);

		if(!g_login)
		{
			printf("register failed\n");
			return -1;
		}

		if(pthread_create(&heartbeat_tid, NULL, heartbeat_thread, (void *)&sockfd) != 0)
		{
			perror("pthread_create heartbeat failed");
			return -1;
		} else {
			printf("Heartbeat thread started\n");
		}
	}
	while(1)
	{
		char cmd[32] = {0};
		printf("input command(add_person/update_person/delete_person/clear_person/quit)\n");
		fgets(cmd, sizeof(cmd), stdin);
		cmd[strcspn(cmd, "\n")] = 0;
		if(strcmp(cmd,"add_person") == 0)
		{
			pthread_mutex_lock(&mutex);

			add_person_request_t person;
			memset(&person, 0, sizeof(person));

			printf("Adding a new person:\n");

			printf("Enter Person ID: \n");
			fgets(person.personId, sizeof(person.personId), stdin);
			person.personId[strcspn(person.personId, "\n")] = 0;

			printf("Enter Person Code: \n");
			fgets(person.personCode, sizeof(person.personCode), stdin);
			person.personCode[strcspn(person.personCode, "\n")] = 0;

			printf("Enter Name: \n");
			fgets(person.name, sizeof(person.name), stdin);
			person.name[strcspn(person.name, "\n")] = 0;

			printf("Enter Type (0-255): \n");
			char type_str[10];
			fgets(type_str, sizeof(type_str), stdin);
			person.type = atoi(type_str);

			printf("Enter ID Number: \n");
			fgets(person.idNum, sizeof(person.idNum), stdin);
			person.idNum[strcspn(person.idNum, "\n")] = 0;

			printf("Enter IC Number: \n");
			fgets(person.icNum, sizeof(person.icNum), stdin);
			person.icNum[strcspn(person.icNum, "\n")] = 0;

			printf("Enter Pass Number: \n");
			char pass_num_str[10];
			fgets(pass_num_str, sizeof(pass_num_str), stdin);
			person.passNum = atoi(pass_num_str);

			printf("Enter Pass Period: \n");
			fgets(person.passPeriod, sizeof(person.passPeriod), stdin);
			person.passPeriod[strcspn(person.passPeriod, "\n")] = 0;

			send_msg(sockfd, REQUEST, ADDPERSON, &person, sizeof(person));
			printf("Add person request sent.\n");
			last_time = time(NULL);
			pthread_mutex_unlock(&mutex);

		}
		else if(strcmp(cmd,"update_person") == 0)
		{
			pthread_mutex_lock(&mutex);
			update_person_request_t person;
			memset(&person, 0, sizeof(person));

			printf("Updating a person:\n");

			printf("Enter Person ID to update:\n");
			fgets(person.personId, sizeof(person.personId), stdin);
			person.personId[strcspn(person.personId, "\n")] = 0;

			printf("Enter New Person Code:\n");
			fgets(person.personCode, sizeof(person.personCode), stdin);
			person.personCode[strcspn(person.personCode, "\n")] = 0;

			printf("Enter New Name:\n");
			fgets(person.name, sizeof(person.name), stdin);
			person.name[strcspn(person.name, "\n")] = 0;

			printf("Enter New Type (0-255):\n ");
			char type_str[10];
			fgets(type_str, sizeof(type_str), stdin);
			person.type = atoi(type_str);

			printf("Enter New ID Number:\n");
			fgets(person.idNum, sizeof(person.idNum), stdin);
			person.idNum[strcspn(person.idNum, "\n")] = 0;

			printf("Enter New IC Number:\n");
			fgets(person.icNum, sizeof(person.icNum), stdin);
			person.icNum[strcspn(person.icNum, "\n")] = 0;

			printf("Enter New Pass Number:\n");
			char pass_num_str[10];
			fgets(pass_num_str, sizeof(pass_num_str), stdin);
			person.passNum = atoi(pass_num_str);

			printf("Enter New Pass Period:\n");
			fgets(person.passPeriod, sizeof(person.passPeriod), stdin);
			person.passPeriod[strcspn(person.passPeriod, "\n")] = 0;

			send_msg(sockfd, REQUEST, UPDATEPERSON, &person, sizeof(person));
			printf("Update person request sent.\n");
			last_time = time(NULL);
			pthread_mutex_unlock(&mutex);
		}
		else if(strcmp(cmd,"delete_person") == 0)
		{
			pthread_mutex_lock(&mutex);
			delete_person_request_t del_req;
			memset(&del_req, 0, sizeof(del_req));

			printf("Deleting a person:\n");
			printf("Enter Person ID to delete:\n");
			fgets(del_req.idSet, sizeof(del_req.idSet), stdin);
			del_req.idSet[strcspn(del_req.idSet, "\n")] = 0;

			send_msg(sockfd, REQUEST, DELPERSON, &del_req, sizeof(del_req));
			printf("Delete person request sent.\n");
			last_time = time(NULL);
			pthread_mutex_unlock(&mutex);
		}
		else if(strcmp(cmd,"clear_person") == 0)
		{
			pthread_mutex_lock(&mutex);
			printf("Clearing all persons...\n");
			send_msg(sockfd, REQUEST, CLRPERSON, NULL, 0);
			printf("Clear persons request sent.\n");
			last_time = time(NULL);
			pthread_mutex_unlock(&mutex);
		}
		else if(strcmp(cmd, "quit") == 0)
			break;
		else 
			printf("Unknown command: %s\n", cmd);
	}
	//4.关闭连接
	close(sockfd);
	return 0;
}
